#ifndef TC_SMSTATE_HPP
#define TC_SMSTATE_HPP

/** \file SmState.hpp 
 * Declarations for the class SmState.
 *
 * (c) Copyright 2003-2006 by Semih Cemiloglu
 * All rights reserved, see COPYRIGHT file for details.
 *
 * $Id: SmState.hpp 119 2006-06-21 04:57:25Z semihc $
 *
 *
 */

#ifndef TC_GLOBAL_HH
# include "Global.hh"
#endif
#ifndef TC_ASSERT_HPP
# include "Assert.hpp"
#endif

namespace TC {


  // Forward declarations
  class SmEvent;
  class SmState;
  class SmIf;


  //! Type of state action for both (FSMs and HSMs). 
  //! It is a pointer to a member function which returns SmState object.
  //! This type is applicable to the entire SmIf hierarchy.
  typedef SmState (SmIf::*SmAction_t)(const SmEvent*);


  /**
   * Various Cast operation to provide platform and compiler
   * independent conversions from SmAction_t to FSM/HSM action
   * type of any state machine.
   * 
   */

  template <typename D>
  TC_INLINE void CastToSmAction(SmAction_t& act, 
                                void (D::*fsmact)(const SmEvent*))
  {
    TC_ASSERT_COMPILE(sizeof(SmAction_t)>=sizeof(fsmact));
#   ifdef TC_VTL_PTR_TO_MEMBER_HACK
     std::memset(&act, 0, sizeof(act));
     std::memcpy(&act, &fsmact, sizeof(fsmact));
#   else
     act = reinterpret_cast<SmAction_t>(fsmact);
#   endif
  }


  template <typename D>
  TC_INLINE void CastToSmAction(SmAction_t& act, 
                                SmState (D::*hsmact)(const SmEvent*))
  {
    TC_ASSERT_COMPILE(sizeof(SmAction_t)>=sizeof(hsmact));
#   ifdef TC_VTL_PTR_TO_MEMBER_HACK
     std::memset(&act, 0, sizeof(act));
     std::memcpy(&act, &hsmact, sizeof(hsmact));
#   else
     act = reinterpret_cast<SmAction_t>(hsmact);
#   endif
  }


  template <typename D>
  TC_INLINE void CastFromSmAction(void (D::*&fsmact)(const SmEvent*),
                                  const SmAction_t& act)
  {
    //! Action type for FSMs
    typedef void (D::*FsmAction_t)(const SmEvent*);
    TC_ASSERT_COMPILE(sizeof(SmAction_t)>=sizeof(FsmAction_t));
#   ifdef TC_VTL_PTR_TO_MEMBER_HACK
     std::memcpy(&fsmact, &act, sizeof(FsmAction_t));
#   else
     fsmact = reinterpret_cast<FsmAction_t>(act);
#   endif
  }


  template <typename D>
  TC_INLINE void CastFromSmAction(SmState (D::*&hsmact)(const SmEvent*),
                                  const SmAction_t& act)
  {
    //! Action type for HSMs
    typedef SmState (D::*HsmAction_t)(const SmEvent*);
    TC_ASSERT_COMPILE(sizeof(SmAction_t)>=sizeof(HsmAction_t));
#   ifdef TC_VTL_PTR_TO_MEMBER_HACK
     std::memcpy(&hsmact, &act, sizeof(HsmAction_t));
#   else
     hsmact = reinterpret_cast<HsmAction_t>(act);
#   endif
  }



  /**
   * A concrete class representing a state of a State Machine.
   * This could be FSM or HSM deriving from base SmIf class.
   */
  class SmState
  {
  public:
    // TYPES
    typedef SmAction_t Action_t;

    // CREATORS
    SmState(Action_t act = 0) : m_ptr(act) {}

    //! Construction by FSMs
    template <typename D>
    SmState(void (D::*mf)(const SmEvent*)) 
    { CastToSmAction(m_ptr, mf); }

    //! Construction by HSMs
    template <typename D> 
    SmState(SmState (D::*mf)(const SmEvent*)) 
    { CastToSmAction(m_ptr, mf); }

  
    // ACCESSORS
    Action_t getAction() const
    { return m_ptr; }

    //! Conversion to the action of the state type
    operator Action_t() const 
    {  return m_ptr;  }
    
    //! Run the action of a FSM state
    template <typename D>
    void runFsmAction(D* sm, const SmEvent* e) const
    { 
      typedef void (D::*FsmAction_t)(const SmEvent*);
      FsmAction_t act;
      CastFromSmAction(act, m_ptr);
      (sm->*act)(e);
    }

    //! Run the action of a HSM state
    template <typename D>
    SmState runHsmAction(D* sm, const SmEvent* e) const
    { 
      typedef SmState (D::*HsmAction_t)(const SmEvent*);
      HsmAction_t act;
      CastFromSmAction(act, m_ptr);
      return (sm->*act)(e);
    }

    // MODIFIERS
    void operator=(Action_t act) 
    { m_ptr = act;  }

    //! Assignment by FSMs
    template <typename D>
    void operator=(void (D::*mf)(const SmEvent*))
    { CastToSmAction(m_ptr, mf); }

    //! Assignment by HSMs
    template <typename D>
    void operator=(SmState (D::*mf)(const SmEvent*))
    { CastToSmAction(m_ptr, mf); }

  private:
    // MEMBERS
    Action_t m_ptr;

  }; // end class




} // end namespace




#endif /* TC_SMSTATE_HPP */
